/*
* Copyright (C) 2020 ~ 2024 chaigec All Rights Reserved.
*
* Author:     chaigec <chaigec@163.com>
* Maintainer: chaigec <chaigec@163.com>

 * Use of this source code is governed by MIT license that can be found in the
 * LICENSE file in the root of the source tree. All contributing project authors
 * may be found in the AUTHORS file in the root of the source tree.
*/

#include "MkHttpApiUt.h"
#include "MkEvent/MkEventPool.h"
#include "MkEvent/MkEvent.h"
#include "MkEvent/MkTimer.h"
#include "MkUtil/MkUtil.h"
#include "MkHttpMedia/MkHttpMediaServer.h"
#include "MkHttpMedia/MkWsFlvPlayer.h"
#include "MkHttp/MkHttpUtil.h"
#include "MkUtil/MkLog.h"
#include "MkMedia/MkFileSource.h"
#include "MkHttp/MkHttpSession.h"
#include "MkEvent/MkTimerPool.h"
#include "MkUtil/MkBase64.h"


CMkHttpTestServer::CMkHttpTestServer(CMkEventPool* pEventPool, CMkTimer* pTimer)
    : CMkHttpApi(pEventPool, pTimer)
{
    //AddTaskPath(MkHttpMethodGet, "task");
    //AddTaskPath(MkHttpMethodPost, "task");
    //AddTaskPath(MkHttpMethodPut, "task");
    //AddTaskPath(MkHttpMethodDelete, "task");
    //AddTaskPath(MkHttpMethodHead, "task");

    //AddTaskPath(MkHttpMethodGet, "serial-task",TRUE);
    //AddTaskPath(MkHttpMethodPost, "serial-task",TRUE);
    //AddTaskPath(MkHttpMethodPut, "serial-task",TRUE);
    //AddTaskPath(MkHttpMethodDelete, "serial-task",TRUE);
    //AddTaskPath(MkHttpMethodHead, "serial-task",TRUE);
}

CMkHttpTestServer::~CMkHttpTestServer()
{

}

Uint32 CMkHttpTestServer::OnRequestJsonParse(const MkHttpMethod& Method, const MkString& Path, const MkMapString& MapQuery, const Json::Value& JsonReq, const MkHttpResponseJsonCb& cb)
{
    if ("error" == Path) {
        Json::Value TmpJson;
        TmpJson["error"] = 1;
        cb(SystemError, TmpJson);
    } else {
        CMkHttpApi::OnRequestJsonParse(Method, Path, MapQuery, JsonReq, cb);
    }
    return NoneError;
}

Uint32 CMkHttpTestServer::OnWebSockekAccessed(CMkHttpSession* pSession)
{
    BroadCastMsg("123");
    return NoneError;
}


void CMkHttpApiUt::SetUp()
{
    m_pHttpTestServer = nullptr;
    m_pEventPool = nullptr;
    m_pTimer = nullptr;
    m_pClient = nullptr;
    m_bClientConnected = FALSE;

    m_bClientConnected = FALSE;
    m_pEventPool = new CMkEventPool;
    m_pEventPool->Start(1);
    m_pTimer = new CMkTimer;
    m_pTimer->StartTimerThread();
    m_WaitHandle = CreateEvent(nullptr, FALSE, FALSE, nullptr);

    m_pHttpTestServer = new CMkHttpTestServer(m_pEventPool, m_pTimer);
    m_pHttpTestServer->SetWebSocketAccessKey("123");
    m_pHttpTestServer->SetMaxConnections(100);
    m_pHttpTestServer->SetMaxWsConnectorSize(1);
    m_pHttpTestServer->SetUserPass("aa", "aa");
    m_pHttpTestServer->SetApiUriPrefix("/api/");
    m_pHttpTestServer->AddTaskPath(MkHttpMethodGet, "task");
    m_pHttpTestServer->AddTaskPath(MkHttpMethodPost, "task");
    m_pHttpTestServer->AddTaskPath(MkHttpMethodPut, "task");
    m_pHttpTestServer->AddTaskPath(MkHttpMethodDelete, "task");
    m_pHttpTestServer->AddTaskPath(MkHttpMethodHead, "task");

    m_pHttpTestServer->AddTaskPath(MkHttpMethodGet, "serial-task", TRUE);
    m_pHttpTestServer->AddTaskPath(MkHttpMethodPost, "serial-task", TRUE);
    m_pHttpTestServer->AddTaskPath(MkHttpMethodPut, "serial-task", TRUE);
    m_pHttpTestServer->AddTaskPath(MkHttpMethodDelete, "serial-task", TRUE);
    m_pHttpTestServer->AddTaskPath(MkHttpMethodHead, "serial-task", TRUE);
    while (1) {
        m_HttpPort = CMkUtil::GetRandomNumber() % 0xFFFF;
        if (NoneError == m_pHttpTestServer->StartServer(m_HttpPort)) {
            break;
        } else {
            m_pHttpTestServer->StopServer();
        }
    }

    MkString BaseAuthor;
    MkBase64Encode(m_pHttpTestServer->GetUserName() + ":" + m_pHttpTestServer->GetPassword(), BaseAuthor);
    BaseAuthor = "Basic " + BaseAuthor;
    m_MapHeader["Authorization"] = BaseAuthor;
}

void CMkHttpApiUt::TearDown()
{
    CMkThread::ThreadSleep(100);
    m_pTimer->StopTimerThread();
    m_pEventPool->Stop();
    m_pHttpTestServer->StopServer();
    MkDelete(m_pHttpTestServer);
    MkDelete(m_pTimer);
    MkDelete(m_pEventPool);
    CloseHandle(m_WaitHandle);
}

TEST_F(CMkHttpApiUt, TaskGetTest)
{
    m_pHttpClient = new CMkHttpClient(m_pEventPool->GetFreeEvent(), m_pTimer, [this](CMkTcpClient* pClient) {
        pClient->DeleteLater();
        SetEvent(m_WaitHandle);
        m_pHttpClient = nullptr;
    });
    m_pHttpClient->SendRequest(MkHttpMethodGet, "http://127.0.0.1:" + std::to_string(m_HttpPort) + m_pHttpTestServer->GetApiUriPrefix() + "task", MkMapString(), "", m_MapHeader, [this](const MkHttpStatusCode& StatusCode, const MkString& Res) {
        EXPECT_EQ(MkHttpStateOk, StatusCode);
        if (m_pHttpClient) {
            m_pHttpClient->Close();
        }
    });
    WaitForSingleObject(m_WaitHandle, 0xFFFF);
}

TEST_F(CMkHttpApiUt, TaskPostTest)
{
    m_pHttpClient = new CMkHttpClient(m_pEventPool->GetFreeEvent(), m_pTimer, [this](CMkTcpClient* pClient) {
        pClient->DeleteLater();
        SetEvent(m_WaitHandle);
        m_pHttpClient = nullptr;
    });
    m_pHttpClient->SendRequest(MkHttpMethodPost, "http://127.0.0.1:" + std::to_string(m_HttpPort) + m_pHttpTestServer->GetApiUriPrefix() + "task", MkMapString(), "", m_MapHeader, [this](const MkHttpStatusCode& StatusCode, const MkString& Res) {
        EXPECT_EQ(MkHttpStateOk, StatusCode);
        if (m_pHttpClient) {
            m_pHttpClient->Close();
        }
    });
    WaitForSingleObject(m_WaitHandle, 0xFFFF);
}

TEST_F(CMkHttpApiUt, TaskPutTest)
{
    m_pHttpClient = new CMkHttpClient(m_pEventPool->GetFreeEvent(), m_pTimer, [this](CMkTcpClient* pClient) {
        pClient->DeleteLater();
        SetEvent(m_WaitHandle);
        m_pHttpClient = nullptr;
    });
    m_pHttpClient->SendRequest(MkHttpMethodPut, "http://127.0.0.1:" + std::to_string(m_HttpPort) + m_pHttpTestServer->GetApiUriPrefix() + "task", MkMapString(), "", m_MapHeader, [this](const MkHttpStatusCode& StatusCode, const MkString& Res) {
        EXPECT_EQ(MkHttpStateOk, StatusCode);
        if (m_pHttpClient) {
            m_pHttpClient->Close();
        }
    });
    WaitForSingleObject(m_WaitHandle, 0xFFFF);
}

TEST_F(CMkHttpApiUt, TaskDeleteTest)
{
    m_pHttpClient = new CMkHttpClient(m_pEventPool->GetFreeEvent(), m_pTimer, [this](CMkTcpClient* pClient) {
        pClient->DeleteLater();
        SetEvent(m_WaitHandle);
        m_pHttpClient = nullptr;
    });
    m_pHttpClient->SendRequest(MkHttpMethodDelete, "http://127.0.0.1:" + std::to_string(m_HttpPort) + m_pHttpTestServer->GetApiUriPrefix() + "task", MkMapString(), "", m_MapHeader, [this](const MkHttpStatusCode& StatusCode, const MkString& Res) {
        EXPECT_EQ(MkHttpStateOk, StatusCode);
        if (m_pHttpClient) {
            m_pHttpClient->Close();
        }
    });
    WaitForSingleObject(m_WaitHandle, 0xFFFF);
}


TEST_F(CMkHttpApiUt, SerialTaskGetTest)
{
    m_pHttpClient = new CMkHttpClient(m_pEventPool->GetFreeEvent(), m_pTimer, [this](CMkTcpClient* pClient) {
        pClient->DeleteLater();
        SetEvent(m_WaitHandle);
        m_pHttpClient = nullptr;
    });
    m_pHttpClient->SendRequest(MkHttpMethodGet, "http://127.0.0.1:" + std::to_string(m_HttpPort) + m_pHttpTestServer->GetApiUriPrefix() + "serial-task", MkMapString(), "", m_MapHeader, [this](const MkHttpStatusCode& StatusCode, const MkString& Res) {
        EXPECT_EQ(MkHttpStateOk, StatusCode);
        if (m_pHttpClient) {
            m_pHttpClient->Close();
        }
    });
    WaitForSingleObject(m_WaitHandle, 0xFFFF);
}

TEST_F(CMkHttpApiUt, SerialTaskPostTest)
{
    m_pHttpClient = new CMkHttpClient(m_pEventPool->GetFreeEvent(), m_pTimer, [this](CMkTcpClient* pClient) {
        pClient->DeleteLater();
        SetEvent(m_WaitHandle);
        m_pHttpClient = nullptr;
    });
    m_pHttpClient->SendRequest(MkHttpMethodPost, "http://127.0.0.1:" + std::to_string(m_HttpPort) + m_pHttpTestServer->GetApiUriPrefix() + "serial-task", MkMapString(), "", m_MapHeader, [this](const MkHttpStatusCode& StatusCode, const MkString& Res) {
        EXPECT_EQ(MkHttpStateOk, StatusCode);
        if (m_pHttpClient) {
            m_pHttpClient->Close();
        }
    });
    WaitForSingleObject(m_WaitHandle, 0xFFFF);
}

TEST_F(CMkHttpApiUt, SerialTaskPutTest)
{
    m_pHttpClient = new CMkHttpClient(m_pEventPool->GetFreeEvent(), m_pTimer, [this](CMkTcpClient* pClient) {
        pClient->DeleteLater();
        SetEvent(m_WaitHandle);
        m_pHttpClient = nullptr;
    });
    m_pHttpClient->SendRequest(MkHttpMethodPut, "http://127.0.0.1:" + std::to_string(m_HttpPort) + m_pHttpTestServer->GetApiUriPrefix() + "serial-task", MkMapString(), "", m_MapHeader, [this](const MkHttpStatusCode& StatusCode, const MkString& Res) {
        EXPECT_EQ(MkHttpStateOk, StatusCode);
        if (m_pHttpClient) {
            m_pHttpClient->Close();
        }
    });
    WaitForSingleObject(m_WaitHandle, 0xFFFF);
}

TEST_F(CMkHttpApiUt, SerialTaskDeleteTest)
{
    m_pHttpClient = new CMkHttpClient(m_pEventPool->GetFreeEvent(), m_pTimer, [this](CMkTcpClient* pClient) {
        pClient->DeleteLater();
        SetEvent(m_WaitHandle);
        m_pHttpClient = nullptr;
    });
    m_pHttpClient->SendRequest(MkHttpMethodDelete, "http://127.0.0.1:" + std::to_string(m_HttpPort) + m_pHttpTestServer->GetApiUriPrefix() + "serial-task", MkMapString(), "", m_MapHeader, [this](const MkHttpStatusCode& StatusCode, const MkString& Res) {
        EXPECT_EQ(MkHttpStateOk, StatusCode);
        if (m_pHttpClient) {
            m_pHttpClient->Close();
        }
    });
    WaitForSingleObject(m_WaitHandle, 0xFFFF);
}

TEST_F(CMkHttpApiUt, AuthorFailTest)
{
    m_pHttpClient = new CMkHttpClient(m_pEventPool->GetFreeEvent(), m_pTimer, [this](CMkTcpClient* pClient) {
        pClient->DeleteLater();
        SetEvent(m_WaitHandle);
        m_pHttpClient = nullptr;
    });
    m_pHttpClient->SendRequest(MkHttpMethodDelete, "http://127.0.0.1:" + std::to_string(m_HttpPort) + m_pHttpTestServer->GetApiUriPrefix() + "aa", MkMapString(), "", MkMapString(), [this](const MkHttpStatusCode& StatusCode, const MkString& Res) {
        EXPECT_EQ(MkHttpStateUnauthorized, StatusCode);
        if (m_pHttpClient) {
            m_pHttpClient->Close();
        }
    });
    WaitForSingleObject(m_WaitHandle, 0xFFFF);
}

TEST_F(CMkHttpApiUt, ErrorTest)
{
    m_pHttpClient = new CMkHttpClient(m_pEventPool->GetFreeEvent(), m_pTimer, [this](CMkTcpClient* pClient) {
        pClient->DeleteLater();
        SetEvent(m_WaitHandle);
        m_pHttpClient = nullptr;
    });
    m_pHttpClient->SendRequest(MkHttpMethodDelete, "http://127.0.0.1:" + std::to_string(m_HttpPort) + m_pHttpTestServer->GetApiUriPrefix() + "error", MkMapString(), "", m_MapHeader, [this](const MkHttpStatusCode& StatusCode, const MkString& Res) {
        EXPECT_EQ(MkHttpStateOk, StatusCode);
        Json::Value JsonRes;
        try {
            Json::CharReaderBuilder b;
            Json::CharReader *reader(b.newCharReader());
            if (reader) {
                MkString errs;
                reader->parse(Res.c_str(), Res.c_str() + Res.size(), &JsonRes, &errs);
                delete reader;
                Uint32 ErrorCode = JsonRes["code"].asUInt();
                EXPECT_EQ(SystemError, ErrorCode);
            }
        } catch (Json::Exception &e) {
            MkErrorLog("body:%s\n", Res.c_str());
            MkErrorLog("json parse error:%s\n", e.what());
        }
        if (m_pHttpClient) {
            m_pHttpClient->Close();
        }
    });
    WaitForSingleObject(m_WaitHandle, 0xFFFF);
}

TEST_F(CMkHttpApiUt, WsTest)
{
    m_pClient = new CMkHttpClient(m_pEventPool->GetFreeEvent(), m_pTimer, [this](CMkTcpClient* pClient) {
        pClient->DeleteLater();
        SetEvent(m_WaitHandle);
        m_pHttpClient = nullptr;
    });
    m_pClient->SetSendPingFlag(TRUE);
    m_pClient->WebSocketConnect("ws://127.0.0.1:" + std::to_string(m_HttpPort) + m_pHttpTestServer->GetWebSocketPath(),
        [this]() {
        m_pClient->SendWebSocketMessage(m_pHttpTestServer->GetWebSocketAccessKey());
    }, [this](const Uint8* pBuf, Uint32 nLen) {
        m_pClient->Close();
    }, []() {});
    WaitForSingleObject(m_WaitHandle, 0xFFFF);
}